package com.alibaba.otter.shared.arbitrate.autoconfigure;

import com.alibaba.otter.shared.arbitrate.ArbitrateEventService;
import com.alibaba.otter.shared.arbitrate.ArbitrateViewService;
import com.alibaba.otter.shared.arbitrate.impl.ArbitrateEventServiceImpl;
import com.alibaba.otter.shared.arbitrate.impl.ArbitrateViewServiceImpl;
import com.alibaba.otter.shared.arbitrate.impl.alarm.AlarmClientService;
import com.alibaba.otter.shared.arbitrate.impl.communication.ArbitrateCommunicationClient;
import com.alibaba.otter.shared.arbitrate.impl.manage.ChannelArbitrateEvent;
import com.alibaba.otter.shared.arbitrate.impl.setl.*;
import com.alibaba.otter.shared.arbitrate.impl.setl.delegate.*;
import com.alibaba.otter.shared.arbitrate.impl.setl.memory.*;
import com.alibaba.otter.shared.arbitrate.impl.setl.rpc.*;
import com.alibaba.otter.shared.arbitrate.impl.setl.zookeeper.*;
import com.alibaba.otter.shared.arbitrate.impl.setl.zookeeper.termin.ErrorTerminProcess;
import com.alibaba.otter.shared.arbitrate.impl.setl.zookeeper.termin.NormalTerminProcess;
import com.alibaba.otter.shared.arbitrate.impl.setl.zookeeper.termin.WarningTerminProcess;
import com.alibaba.otter.shared.common.model.config.pipeline.PipelineParameter;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;

import java.util.HashMap;
import java.util.Map;

@Configuration(proxyBeanMethods = false)
@EnableAsync
public class ArbitrateEventConfiguration {


    @Bean
    public ArbitrateViewService arbitrateViewService() {
        return new ArbitrateViewServiceImpl();
    }

    @Bean
    public ToolArbitrateEvent toolEvent() {
        return new ToolArbitrateEvent();
    }

    @Bean
    public MainStemArbitrateEvent mainStemEvent() {
        return new MainStemArbitrateEvent();
    }

    /**
     * termin process bean
     */
    @Bean
    public NormalTerminProcess normalTerminProcess() {
        return new NormalTerminProcess();
    }

    @Bean
    public WarningTerminProcess warningTerminProcess(AlarmClientService alarmClientService) {
        WarningTerminProcess warningTerminProcess = new WarningTerminProcess();
        warningTerminProcess.setAlarmClientService(alarmClientService);
        return warningTerminProcess;
    }

    @Bean
    public ErrorTerminProcess errorTerminProcess(NormalTerminProcess normalTerminProcess) {
        ErrorTerminProcess errorTerminProcess = new ErrorTerminProcess();
        errorTerminProcess.setNormalTerminProcess(normalTerminProcess);
        return errorTerminProcess;
    }

    /**
     * rpc bean
     */
    @Bean
    public TerminateRpcArbitrateEvent terminRpcEvent(ArbitrateCommunicationClient arbitrateCommunicationClient,
                                                     NormalTerminProcess normalTerminProcess,
                                                     WarningTerminProcess warningTerminProcess,
                                                     ChannelArbitrateEvent channelEvent) {
        TerminateRpcArbitrateEvent terminRpcArbitrateEvent = new TerminateRpcArbitrateEvent();
        terminRpcArbitrateEvent.setNormalTerminProcess(normalTerminProcess);
        terminRpcArbitrateEvent.setWarningTerminProcess(warningTerminProcess);
        terminRpcArbitrateEvent.setChannelEvent(channelEvent);
        terminRpcArbitrateEvent.setArbitrateCommmunicationClient(arbitrateCommunicationClient);
        return terminRpcArbitrateEvent;
    }

    @Bean
    public SelectRpcArbitrateEvent selectRpcEvent(RpcStageEventDispatcher rpcStageEventDispatcher) {
        SelectRpcArbitrateEvent selectRpcArbitrateEvent = new SelectRpcArbitrateEvent();
        selectRpcArbitrateEvent.setRpcStageEventDispatcher(rpcStageEventDispatcher);
        return selectRpcArbitrateEvent;
    }

    @Bean
    public ExtractRpcArbitrateEvent extractRpcEvent(RpcStageEventDispatcher rpcStageEventDispatcher) {
        ExtractRpcArbitrateEvent extractRpcArbitrateEvent = new ExtractRpcArbitrateEvent();
        extractRpcArbitrateEvent.setRpcStageEventDispatcher(rpcStageEventDispatcher);
        return extractRpcArbitrateEvent;
    }

    @Bean
    public TransformRpcArbitrateEvent transformRpcEvent(RpcStageEventDispatcher rpcStageEventDispatcher) {
        TransformRpcArbitrateEvent transformRpcArbitrateEvent = new TransformRpcArbitrateEvent();
        transformRpcArbitrateEvent.setRpcStageEventDispatcher(rpcStageEventDispatcher);
        return transformRpcArbitrateEvent;
    }

    @Bean
    public LoadRpcArbitrateEvent loadRpcEvent(@Qualifier("terminRpcEvent") TerminateRpcArbitrateEvent terminRpcEvent, RpcStageEventDispatcher rpcStageEventDispatcher) {
        LoadRpcArbitrateEvent loadRpcArbitrateEvent = new LoadRpcArbitrateEvent();
        loadRpcArbitrateEvent.setTerminEvent(terminRpcEvent);
        loadRpcArbitrateEvent.setRpcStageEventDispatcher(rpcStageEventDispatcher);
        return loadRpcArbitrateEvent;
    }

    /**
     * memory bean
     */
    @Bean
    public SelectMemoryArbitrateEvent selectMemoryEvent() {
        return new SelectMemoryArbitrateEvent();
    }

    @Bean
    public ExtractMemoryArbitrateEvent extractMemoryEvent() {
        return new ExtractMemoryArbitrateEvent();
    }

    @Bean
    public TransformMemoryArbitrateEvent transformMemoryEvent() {
        return new TransformMemoryArbitrateEvent();
    }

    @Bean
    public TerminateMemoryArbitrateEvent terminMemoryEvent(ArbitrateCommunicationClient arbitrateCommunicationClient,
                                                           WarningTerminProcess warningTerminProcess,
                                                           ChannelArbitrateEvent channelEvent) {
        TerminateMemoryArbitrateEvent terminMemoryArbitrateEvent = new TerminateMemoryArbitrateEvent();
        terminMemoryArbitrateEvent.setChannelEvent(channelEvent);
        terminMemoryArbitrateEvent.setWarningTerminProcess(warningTerminProcess);
        terminMemoryArbitrateEvent.setArbitrateCommmunicationClient(arbitrateCommunicationClient);
        return terminMemoryArbitrateEvent;
    }

    @Bean
    public LoadMemoryArbitrateEvent loadMemoryEvent(@Qualifier("terminMemoryEvent") TerminateMemoryArbitrateEvent terminMemoryEvent) {
        LoadMemoryArbitrateEvent loadMemoryArbitrateEvent = new LoadMemoryArbitrateEvent();
        loadMemoryArbitrateEvent.setTerminEvent(terminMemoryEvent);
        return loadMemoryArbitrateEvent;
    }

    @Bean
    public RpcStageEventDispatcher rpcStageEventDispatcher(ArbitrateCommunicationClient arbitrateCommunicationClient) {
        RpcStageEventDispatcher rpcStageEventDispatcher = new RpcStageEventDispatcher();
        rpcStageEventDispatcher.setArbitrateCommmunicationClient(arbitrateCommunicationClient);
        return rpcStageEventDispatcher;
    }

    /**
     * distuributed bean
     */
    @Bean
    public SelectZooKeeperArbitrateEvent selectZooKeeperEvent() {
        return new SelectZooKeeperArbitrateEvent();
    }


    @Bean
    public ExtractZooKeeperArbitrateEvent extractZooKeeperEvent() {
        return new ExtractZooKeeperArbitrateEvent();
    }

    @Bean
    public TransformZooKeeperArbitrateEvent transformZooKeeperEvent() {
        return new TransformZooKeeperArbitrateEvent();
    }

    @Bean
    public TerminateZooKeeperArbitrateEvent terminZooKeeperEvent(ArbitrateCommunicationClient arbitrateCommunicationClient,
                                                                 NormalTerminProcess normalTerminProcess,
                                                                 WarningTerminProcess warningTerminProcess,
                                                                 ChannelArbitrateEvent channelEvent) {
        TerminateZooKeeperArbitrateEvent terminZooKeeperArbitrateEvent = new TerminateZooKeeperArbitrateEvent();
        terminZooKeeperArbitrateEvent.setChannelEvent(channelEvent);
        terminZooKeeperArbitrateEvent.setNormalTerminProcess(normalTerminProcess);
        terminZooKeeperArbitrateEvent.setWarningTerminProcess(warningTerminProcess);
        terminZooKeeperArbitrateEvent.setArbitrateCommmunicationClient(arbitrateCommunicationClient);
        return terminZooKeeperArbitrateEvent;
    }

    @Bean
    public LoadZooKeeperArbitrateEvent loadZooKeeperEvent(@Qualifier("terminZooKeeperEvent") TerminateZooKeeperArbitrateEvent terminZooKeeperEvent) {
        LoadZooKeeperArbitrateEvent loadZooKeeperArbitrateEvent = new LoadZooKeeperArbitrateEvent();
        loadZooKeeperArbitrateEvent.setTerminEvent(terminZooKeeperEvent);
        return loadZooKeeperArbitrateEvent;
    }

    /**
     * delegate bean
     */
    @Bean
    public SelectDelegateArbitrateEvent selectEvent(@Qualifier("selectMemoryEvent") SelectMemoryArbitrateEvent selectMemoryEvent,
                                                    @Qualifier("selectRpcEvent") SelectRpcArbitrateEvent selectRpcEvent,
                                                    @Qualifier("selectZooKeeperEvent") SelectZooKeeperArbitrateEvent selectZooKeeperEvent) {
        SelectDelegateArbitrateEvent selectDelegateArbitrateEvent = new SelectDelegateArbitrateEvent();
        Map<PipelineParameter.ArbitrateMode, SelectArbitrateEvent> delegate = new HashMap<>();

        delegate.put(PipelineParameter.ArbitrateMode.MEMORY, selectMemoryEvent);
        delegate.put(PipelineParameter.ArbitrateMode.RPC, selectRpcEvent);
        delegate.put(PipelineParameter.ArbitrateMode.ZOOKEEPER, selectZooKeeperEvent);
        selectDelegateArbitrateEvent.setDelegate(delegate);

        return selectDelegateArbitrateEvent;
    }


    @Bean
    public ExtractDelegateArbitrateEvent extractEvent(ExtractMemoryArbitrateEvent extractMemoryEvent,
                                                      ExtractRpcArbitrateEvent extractRpcEvent,
                                                      ExtractZooKeeperArbitrateEvent extractZooKeeperEvent) {
        ExtractDelegateArbitrateEvent extractDelegateArbitrateEvent = new ExtractDelegateArbitrateEvent();
        Map<PipelineParameter.ArbitrateMode, ExtractArbitrateEvent> delegate = new HashMap<>();

        delegate.put(PipelineParameter.ArbitrateMode.MEMORY, extractMemoryEvent);
        delegate.put(PipelineParameter.ArbitrateMode.RPC, extractRpcEvent);
        delegate.put(PipelineParameter.ArbitrateMode.ZOOKEEPER, extractZooKeeperEvent);
        extractDelegateArbitrateEvent.setDelegate(delegate);

        return extractDelegateArbitrateEvent;
    }


    @Bean
    public TransformDelegateArbitrateEvent transformEvent(TransformMemoryArbitrateEvent transformMemoryEvent,
                                                          TransformRpcArbitrateEvent transformRpcEvent,
                                                          TransformZooKeeperArbitrateEvent transformZooKeeperEvent) {
        TransformDelegateArbitrateEvent transformDelegateArbitrateEvent = new TransformDelegateArbitrateEvent();
        Map<PipelineParameter.ArbitrateMode, TransformArbitrateEvent> delegate = new HashMap<>();

        delegate.put(PipelineParameter.ArbitrateMode.MEMORY, transformMemoryEvent);
        delegate.put(PipelineParameter.ArbitrateMode.RPC, transformRpcEvent);
        delegate.put(PipelineParameter.ArbitrateMode.ZOOKEEPER, transformZooKeeperEvent);
        transformDelegateArbitrateEvent.setDelegate(delegate);

        return transformDelegateArbitrateEvent;
    }


    @Bean
    public LoadDelegateArbitrateEvent loadEvent(LoadMemoryArbitrateEvent loadMemoryEvent,
                                                LoadRpcArbitrateEvent loadRpcEvent,
                                                LoadZooKeeperArbitrateEvent loadZooKeeperEvent) {
        LoadDelegateArbitrateEvent loadDelegateArbitrateEvent = new LoadDelegateArbitrateEvent();
        Map<PipelineParameter.ArbitrateMode, LoadArbitrateEvent> delegate = new HashMap<>();

        delegate.put(PipelineParameter.ArbitrateMode.MEMORY, loadMemoryEvent);
        delegate.put(PipelineParameter.ArbitrateMode.RPC, loadRpcEvent);
        delegate.put(PipelineParameter.ArbitrateMode.ZOOKEEPER, loadZooKeeperEvent);
        loadDelegateArbitrateEvent.setDelegate(delegate);

        return loadDelegateArbitrateEvent;
    }


    @Bean
    public TerminateDelegateArbitrateEvent terminEvent(TerminateMemoryArbitrateEvent terminMemoryEvent,
                                                       @Qualifier("terminRpcEvent") TerminateRpcArbitrateEvent terminRpcEvent,
                                                       @Qualifier("terminZooKeeperEvent") TerminateZooKeeperArbitrateEvent terminZooKeeperEvent) {
        TerminateDelegateArbitrateEvent terminDelegateArbitrateEvent = new TerminateDelegateArbitrateEvent();
        Map<PipelineParameter.ArbitrateMode, TerminateArbitrateEvent> delegate = new HashMap<>();

        delegate.put(PipelineParameter.ArbitrateMode.MEMORY, terminMemoryEvent);
        delegate.put(PipelineParameter.ArbitrateMode.RPC, terminRpcEvent);
        delegate.put(PipelineParameter.ArbitrateMode.ZOOKEEPER, terminZooKeeperEvent);
        terminDelegateArbitrateEvent.setDelegate(delegate);

        return terminDelegateArbitrateEvent;
    }


    @Bean
    public ArbitrateEventService arbitrateEventService(@Qualifier("mainStemEvent") MainStemArbitrateEvent mainStemEvent,
                                                       @Qualifier("selectEvent") SelectArbitrateEvent selectEvent,
                                                       @Qualifier("extractEvent") ExtractArbitrateEvent extractEvent,
                                                       @Qualifier("transformEvent") TransformArbitrateEvent transformEvent,
                                                       @Qualifier("loadEvent") LoadArbitrateEvent loadEvent,
                                                       @Qualifier("terminEvent") TerminateArbitrateEvent terminEvent,
                                                       @Qualifier("toolEvent") ToolArbitrateEvent toolEvent) {
        ArbitrateEventServiceImpl arbitrateEventService = new ArbitrateEventServiceImpl();
        arbitrateEventService.setMainStemEvent(mainStemEvent);
        arbitrateEventService.setSelectEvent(selectEvent);
        arbitrateEventService.setExtractEvent(extractEvent);
        arbitrateEventService.setTransformEvent(transformEvent);
        arbitrateEventService.setLoadEvent(loadEvent);
        arbitrateEventService.setTerminateEvent(terminEvent);
        arbitrateEventService.setToolEvent(toolEvent);
        return arbitrateEventService;
    }


}
